/*
 Copyright (c) 2007-2008 The Regents of the University of California.
 All rights reserved.

 Permission is hereby granted, without written agreement and without
 license or royalty fees, to use, copy, modify, and distribute this
 software and its documentation for any purpose, provided that the
 above copyright notice and the following two paragraphs appear in all
 copies of this software and that appropriate acknowledgments are made
 to the research of the COSI group.

 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.

 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
 ENHANCEMENTS, OR MODIFICATIONS.

 Author : Alessandro Pinto <apinto@eecs.berkeley.edu>
 University of California, Berkeley
 545 Cory Hall, Berkeley, CA 94720
 */
#include "Report.h"

namespace cosi {

namespace io {

namespace onchipcommunication {

using namespace std ;

void PrintReport( string pFileName , ProjectParser* pPrj , cosi::platforms::onchipcommunication::NocPlatformInterface* pPlt ,  cosi::algorithms::onchipcommunication::NetworkCost* pCost ) {

  //----------------------------------------------------------
  //                Open File
  //----------------------------------------------------------

  ofstream f ;
  f.open( pFileName.c_str( ) ) ;

  f<< "Generated by COSI OCC 1.3 " << endl ;
  f<< endl ;
  // TODO : add the date when this report was generated
  f<< "Report for project " << pPrj->GetProjectName( ) << endl << endl ;


  //----------------------------------------------------------
  //        Write some interesting technology parameters
  //----------------------------------------------------------
  f << "  " << "Library file  " << pPrj->GetLibraryFileName( )  << endl ;
  f << "  " << "Library  " << pPrj->GetLibraryName( ) << endl ;
  f << "  " << "Fclk  " << pPlt->OperatingFrequency( ) << endl ;
  f << "  " << "Critical sequential length (Lst) " << pPlt->WireLst( )*1e3 << " mm" <<  endl ;
  //f << "  " << "Optimal buffer size " << pPlt->Kopt( ) << "  " <<  "Critical sequential length (Lst) " << pPlt->WireLst( )*1e3 << " mm" <<  endl ;
  f << "  " << "Dynamic energy per unit length per bit " << pPlt->WireEnergy( )*1e12 << " pJ" << endl ;
  f << "  " << "Leaakge power per unit length per bit " << pPlt->WireLeakage( )*1e9 << " nW" << endl ;
  f << "  " << "Wire pitch for global wires  " << pPlt->WirePitch( )*1e9 << " nm" << endl ;
  f << "  " << "Flit width  " << pPlt->FlitWidth( ) << " bits" << endl ;
  f << "  " << "Dynamic energy per flit of a " << pPlt->MaxInDegree( ) << "x" << pPlt->MaxOutDegree( ) << " router  " << pPlt->RouterEnergy( pPlt->MaxInDegree() , pPlt->MaxOutDegree( ) )*1e12 << " pJ" << endl ;
  f << "  " << "Area of a " << pPlt->MaxInDegree( ) << "x" << pPlt->MaxOutDegree( ) << " router  " << pPlt->RouterArea( pPlt->MaxInDegree() , pPlt->MaxOutDegree( ) )*1e12  << " um^2" << endl ;

  f << endl ;

  //----------------------------------------------------------
  //                Write synthesis constraints
  //----------------------------------------------------------
  f << "Synthesis constraints " << endl ;
  f << "  " << "Spare area during floorplannig  " << pPrj->GetSpareArea( ) << " \% of block area" << endl ;
  f << "  " << "Step size  " << pPrj->GetStep( ) << " of Lst " << endl ;
  f << "  " << "Source maximum output degree  " << pPlt->SourceOutDegree( ) << endl ;
  f << "  " << "Destination maximum input degree  " << pPlt->DestInDegree( ) << endl ;
  f << "  " << "Rotuer maximum input degree  " << pPlt->MaxInDegree( ) << endl ;
  f << "  " << "Router maximum output degree  " << pPlt->MaxOutDegree( ) << endl ;
  f << "  " << "Switching activity  " << pPlt->SwitchingFactor( ) << endl ;
  f << "  " << "Relative power vs. area cost  " << pPlt->PowerVsArea( ) << endl ;
//  f << "  " << "Allow point-to-point connections ?  " ;
//  if ( pPlt->AllowPtP() )
//    f << "Yes" << endl ;
//  else
//    f << "No" << endl ;

  f << endl ;

  //----------------------------------------------------------
  //                Write network costs and performances
  //----------------------------------------------------------
  f << "Power report " << endl ;
  f << "  " << "Wires : " << endl;
  f << "    " << "Dynamic power = " << pCost->GetWireDynamicPower( ) << " W" << endl ;
  f << "    " << "Static  power = " << pCost->GetWireStaticPower( ) << " W"<< endl ;
  f << "    " << "Total   power = " << pCost->GetWireTotalPower( ) << " W"<< endl ;
  f << "  " << "Routers : " << endl;
  f << "    " << "Dynamic power = " << pCost->GetRouterDynamicPower( ) << " W"<< endl ;
  f << "    " << "Static  power = " << pCost->GetRouterStaticPower( ) << " W"<< endl ;
  f << "    " << "Total   power = " << pCost->GetRouterTotalPower( ) << " W"<< endl ;
//  f << "  " << "Interfaces : " << endl ;
//  f << "    " << "Total   power = " << pCost->GetInterfacePower( ) << " W" << endl ;
  f << "    " << "                ---------------------" << endl ;
  f << "  " <<   "Network dynamic power =   " <<  pCost->GetRouterDynamicPower( ) + pCost->GetWireDynamicPower( ) << endl;
  f << "  " <<   "Network power =   " <<  pCost->GetRouterTotalPower( ) + pCost->GetWireTotalPower( )  << endl;


  f << endl ;
  f << "Area report " << endl ;
  //f << "Chip dimensions " << pPlt->GetChipW( )*1e3 << "x" << pPlt->GetChipH( )*1e3 << " mm^2" << endl ;
  f << "  " << "Wires : " << endl;
  f << "    " << "Minimum length  " << pCost->GetMinDist( )*1e3 << " mm" << endl;
  f << "    " << "Maximum length  " << pCost->GetMaxDist( )*1e3 << " mm" << endl;
  f << "    " << "Total length  " << pCost->GetTotalDist( )*1e3 << " mm" << endl;
  f << "    " << "Average length  " << pCost->GetAverageDist( )*1e3 << " mm" << endl;
  f << "    " << "Wiring Area  " << pCost->GetWireWiringArea()*1e6 << " mm^2" << endl ;
  f << "    " << "Device Area  " << pCost->GetWireDeviceArea()*1e6 << " mm^2" << endl ;
  f << "    " << "Total Area   = " << pCost->GetWireArea( )*1e6 << " mm^2" << endl ;
  f << "  " << "Routers : " << endl;
  f << "    " << "Minimum input degree  " << pCost->GetMinInDegree( ) << endl ;
  f << "    " << "Maximum input degree  " << pCost->GetMaxInDegree( ) << endl ;
  f << "    " << "Average input degree  " << pCost->GetAverageInDegree( ) << endl ;
  f << endl ;
  f << "    " << "Minimum output degree  " << pCost->GetMinOutDegree( ) << endl ;
  f << "    " << "Maximum output degree  " << pCost->GetMaxOutDegree( ) << endl ;
  f << "    " << "Average output degree  " << pCost->GetAverageOutDegree( ) << endl ;
  f << endl ;
  f << "    " << pCost->GetNnodes( ) << "  nodes"  << endl ;

  //f << "    " << pCost->GetNrouter( ) << "  routers and " << pCost->GetNlatch( ) << " latches " << endl ;
  f << "    " << "Total area   = " << pCost->GetRouterArea( )*1e6 << "  mm^2" << endl ;
  f << endl ;
//  f << "  " << "Interfaces : " << endl;
//  f << "    " << "Total area   = " << pCost->GetInterfaceArea( )*1e6 << "  mm^2" << endl ;
  f << "    " << "            --------------------" << endl ;
  f << "  " <<   "Network area =   " << ( pCost->GetWireArea( ) + pCost->GetRouterArea( ) ) *1e6 << "  mm^2" << endl  ;
  f<< endl ;

  f<< "Delay report " << endl;
  f<< "  " << "Minimum number of hops  " << pCost->GetMinHop( ) << endl ;
  f<< "  " << "Maximum number of hops  " << pCost->GetMaxHop( ) << endl ;
  f<< "  " << "Average number of hops  " << pCost->GetAverageHop( ) << endl ;
  f<< endl ;


//    f << "List of paths with delay violation " << endl ;
//    map< pair<int,int> , pair<int,int> > Paths = pCost->GetViolatedPaths( ) ;
//    map< pair<int,int> , pair<int,int> >::iterator PathIt ;
//    for( PathIt = Paths.begin( ) ; PathIt != Paths.end( ) ; PathIt++ ) {
//      int S , D , L , H ;
//      S = (PathIt->first).first ;
//      D = (PathIt->first).second ;
//      L = (PathIt->second).first ;
//      H = (PathIt->second).second ;
//      f << "   " << S << " to " << D << " T = " << L << "   H = " << H << endl ;
//    }


//  f << "Point-to-point estimated metrics:" << endl ;
//  f << "  " << "Power : " << pCost->GetPtpPower() << endl ;
//  f << "  " << "Area : " << pCost->GetPtpArea() << endl ;

  f.close( ) ;

}

void AppendRow( string pFileName , ProjectParser* pPrj , cosi::platforms::onchipcommunication::NocPlatformInterface* pPlt ,  cosi::algorithms::onchipcommunication::NetworkCost* pCost ) {

  //----------------------------------------------------------
  //                Open File
  //----------------------------------------------------------

  ofstream f ;
  f.open( pFileName.c_str( ) , fstream::app ) ;


  //PdynW PleakW PtotW PdynR PleakR PtotR Ptot

  f << pPrj->GetProjectName( ) << "\t" ;

  f << pCost->GetWireDynamicPower( ) << "\t" ;
  f << pCost->GetWireStaticPower( ) << "\t" ;
  f << pCost->GetWireTotalPower( ) << "\t" ;
  f << pCost->GetRouterDynamicPower( ) << "\t" ;
  f << pCost->GetRouterStaticPower( ) << "\t" ;
  f << pCost->GetRouterTotalPower( ) << "\t" ;
  f << pCost->GetRouterTotalPower( ) + pCost->GetWireTotalPower( ) << "\t" ;

  //Awiring Adevide AtotW AR Atot

  f <<pCost->GetWireWiringArea()*1e6 << "\t" ;
  f << pCost->GetWireDeviceArea()*1e6 << "\t" ;
  f <<  pCost->GetWireArea( )*1e6<< "\t" ;
  f <<pCost->GetRouterArea( )*1e6 << "\t" ;
  f <<( pCost->GetWireArea( ) + pCost->GetRouterArea( ) ) *1e6 << "\t" ;

  //Maxin Avgin Maxout Avgout

  f << pCost->GetMaxInDegree( ) << "\t" ;
  f << pCost->GetAverageInDegree( ) << "\t" ;
  f << pCost->GetMaxOutDegree( ) << "\t" ;
  f << pCost->GetAverageOutDegree( ) << "\t" ;
  //MaxHop AvgHop

  f<< pCost->GetMaxHop( ) << "\t" ;
  f<< pCost->GetAverageHop( ) << "\t" ;
  f<< endl ;

  //in2 in3... in10 out2 out3... out10

  f.close( ) ;

}
}
}
}
